# -*- coding: utf-8 -*-

from sympy import Union, Interval, S, simplify
from sympy.abc import x
from mathsolver.functions.hanshu.dingyiyu import QiuDingYiYu
from mathsolver.functions.base.base import BaseFunction, new_latex
from mathsolver.functions.base.objects import BaseEq, BaseFunc, BasePieceFunc, BaseSinFunc
from mathsolver.functions.hanshu.qujueduizhi import QuJueDuiZhi


class OddEven(BaseFunction):
    def __init__(self):
        super(OddEven, self).__init__()
        self.numOdd = 0
        self.numEven = 0
        self.hasZero = False
        self.fZero = 0

    @staticmethod
    def is_symmetrical_interval(interval):
        """
        判断区间是否关于原点对称
        :param interval: 区间
        :return: 是否对称
        """
        # print "要判断的区间是：", interval
        if interval.args[0].is_Number:  # 区间只有一段
            return interval.args[0] == - interval.args[1] and interval.args[2] == interval.args[3]
        else:  # 区间有多段
            mirror_interval = S.EmptySet  # 镜像区间
            for arg in interval.args:
                mirror_interval = Union(mirror_interval, Interval(-arg.args[1], -arg.args[0], arg.args[3], arg.args[2]))
            # print "镜像区间是：", mirror_interval
            return interval == mirror_interval

    def solver(self, *args):
        arg0 = args[0]
        # 补充：分段函数
        if isinstance(arg0, BasePieceFunc):
            return self.solver_piecewise(*arg0.expression)

        if isinstance(arg0, BaseEq):
            _, f = args[0].sympify()
        elif isinstance(arg0, BaseFunc):
            f = arg0.expression
        elif isinstance(arg0, BaseSinFunc):
            f = arg0.expression
        else:
            raise ValueError("input must be either BaseEq or BaseFunc")

        thisdomain = QiuDingYiYu().solver(arg0)  # 求定义域
        # thisdomain = get_dingyiyu().getXdomain(f, target_symbol)  # 求定义域
        self.steps.append(["", "f(x)定义域为 %s" % thisdomain])
        self.label.add("判断函数的奇偶性")
        # 判断定义域是否对称
        if not self.is_symmetrical_interval(thisdomain):
            self.steps.append(["", "定义域不关于原点对称，函数是非奇非偶函数。"])
            self.output.append("非奇非偶函数")
            return self
        # 含绝对值时,首先在定义域上去绝对值,对函数进行化简
        if "Abs" in str(f):
            _, result = QuJueDuiZhi().elim_abs(f, thisdomain)
            if len(result) == 1:  # 化简后函数只有一段
                self.steps.append(["", "化简f(x)= %s = %s" % (f, new_latex(result[0][2]))])
                f = result[0][2]

        # print "判断f(x)和f(-x)的关系："
        fminusx = f.subs(x, -x)
        self.steps.append(["f(x)= %s" % new_latex(f), "f(-x)=%s" % new_latex(fminusx)])
        if simplify(f + fminusx) == 0:
            self.steps.append(["", "因为f(-x)=-f(x)，所以函数是奇函数。"])
            self.output.append("奇函数")
            return self
        if simplify(f - fminusx) == 0:
            self.steps.append(["", "因为f(-x)=f(x)，所以函数是偶函数。"])
            self.output.append("偶函数")
            return self
        self.steps.append(["", "f(-x) ≠ f(x)且f(-x) ≠ -f(x), 函数是非奇非偶函数。"])
        self.output.append("非奇非偶函数")
        return self

    # 从区间到不等式
    @staticmethod
    def interval2inequality(interval):
        ll = interval.args[0]
        r = interval.args[1]
        lopen = interval.args[2]
        ropen = interval.args[3]
        if ll.is_finite and r.is_finite:
            if lopen and ropen:
                return x > ll, x < r
            elif not lopen and ropen:
                return x >= ll, x < r
            elif lopen and not ropen:
                return x > ll, x <= r
            else:
                return x >= ll, x <= r
        elif ll.is_finite and not r.is_finite:
            if lopen:
                return x > ll
            else:
                return x >= ll
        elif not ll.is_finite and r.is_finite:
            if ropen:
                return x < r
            else:
                return x <= r
        else:
            print("x的范围为R")

    @staticmethod
    def get_minusx_domain(interval):
        return Interval(-interval.args[1], -interval.args[0], interval.args[3], interval.args[2])

    @staticmethod
    def interval_has_zero(interval):
        return Interval(0, 0).is_subset(interval)

    def interval_delete_zero(self, interval):
        if not self.interval_has_zero(interval):
            return interval
        if interval.args[0] == 0:
            return Interval(0, interval.args[1], True, interval.args[3])
        elif interval.args[1] == 0:
            return Interval(interval.args[0], 0, interval.args[2], True)
        return interval

    def solver_piecewise(self, *args):
        self.label.add("判断函数的奇偶性")
        thisdomain = S.EmptySet  # 分段函数的定义域
        for arg in args:
            # thisdomain = thisdomain.union(solveset(arg[1], x, S.Reals))
            thisdomain = thisdomain.union(arg[1])
        self.steps.append(["", "f(x)定义域为 %s" % new_latex(thisdomain)])
        # 判断定义域是否对称
        if not self.is_symmetrical_interval(thisdomain):
            self.steps.append(["", "定义域不关于原点对称，函数是非奇非偶函数。"])

        for arg in args:
            fx = arg[0]
            domain = arg[1]
            # 如果区间端点包含0, 则把0去掉, 之后再单独做判断
            # 例如将[0, +oo)变为(0, +oo)
            # 另一种情况, 中间包含0, 例如(-1, 1), 这种不做修改, 直接判断
            if self.interval_has_zero(domain):
                self.hasZero = True
                domain = self.interval_delete_zero(domain)
                self.fZero = fx.subs(x, 0)
            # domain_minusx表示-x的取值区间
            domain_minusx = self.get_minusx_domain(domain)

            self.steps.append(["", "若 %s 则 %s" % (new_latex(self.interval2inequality(domain)), new_latex(self.interval2inequality(domain_minusx).subs(x, -x)))])

            # 找到-x对应区间的函数,并将-x带入
            for argm in args:
                if domain_minusx.is_subset(argm[1]):
                    fminusx = argm[0].subs(x, -x)
                    if fminusx == fx:
                        self.numEven += 1
                        self.steps.append(["", "f(-x) = %s = = f(x)" % fminusx])
                    elif fminusx == -fx:
                        self.numOdd += 1
                        self.steps.append(["", "f(-x) = %s = = -f(x)" % fminusx])
                    break

        if self.numEven == len(args):
            self.steps.append(["", "对任意的x ∈ %s 都有f(-x)=f(x)，所以函数是偶函数。" % thisdomain])
            self.output.append("偶函数")
            return self
        elif self.numOdd == len(args):
            if self.hasZero:
                if self.fZero != 0:
                    self.steps.append(["", "f(0) = %s ≠ 0, 函数是非奇非偶函数。"])
                    self.output.append("非奇非偶函数")
                    return self
                else:
                    self.steps.append(["", "f(0) = 0"])
            self.steps.append(["", "对任意的x ∈ %s，都有f(-x)=-f(x)，所以函数是奇函数。" % thisdomain])
            self.output.append("奇函数")
            return self


if __name__ == '__main__':
    pass
